package com.ccsoft.annoreflect.service.impl;

import com.ccsoft.annoreflect.anno.TableField;
import com.ccsoft.annoreflect.service.BaseService;
import com.ccsoft.annoreflect.utils.DBUtils;
import com.ccsoft.annoreflect.utils.SQLProvider;

import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chanchaw
 * @create 2022-09-23 15:27
 */
public class BaseServiceImpl<T> implements BaseService<T> {

    private Connection connection = DBUtils.getConnection();
    private SQLProvider sqlProvider = new SQLProvider();

    @Override
    public List<T> queryList(Object obj) throws InvocationTargetException, IllegalAccessException, SQLException, InstantiationException {
        final ParameterizedType type = (ParameterizedType)this.getClass().getGenericSuperclass();
        Class<T> modelClazz = (Class<T>)type.getActualTypeArguments()[0];// 传入的泛型T可以是数组，这里取第一个类型

        // 构建查询 sql 并查询
        String sql = sqlProvider.getQuerySQL(obj);
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql);


        List<T> result = new ArrayList<>();
        Field[] fields = modelClazz.getDeclaredFields();
        while(resultSet.next()){
            Object instance = modelClazz.newInstance();

            for(Field field:fields){
                // 如果实体类属性没有设置字段注解@TableField，则以属性名称作为字段名称
                // 这样可以兼容 sql 语句中 as 出来的字段 - 该字段不可添加@TableField，否则增删时会带入
                TableField fieldAnno = field.getAnnotation(TableField.class);
                String fieldName = "";
                if(fieldAnno == null) fieldName = field.getName();
                else fieldName = fieldAnno.fieldName();

                // 如果实体类中额外添加的属性，在实际 sql 语句中没有对应字段
                // 则取字段值时会报错，这种情况直接跳出本次，进入下次循环
                Object fieldValue = null;
                try{
                    fieldValue = resultSet.getObject(fieldName, field.getType());
                }catch (SQLException e){
                    continue;
                }

                // 将当前字段的值写入实体对象
                String setterMethodName = "set" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
                Method setterMethod = null;
                try {// 属性没有对应的 setter 方法则继续下一个循环
                    setterMethod = modelClazz.getMethod(setterMethodName,field.getType());
                } catch (NoSuchMethodException e) {
                    continue;
                }
                setterMethod.invoke(instance,fieldValue);// 对象resultSet给属性field赋值
            }
            result.add((T)instance);
        }
        return result;
    }

    @Override
    public int update(Object obj) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, SQLException {
        String sql = sqlProvider.getUpdateSQLSelective(obj);
        Statement statement = connection.createStatement();
        return statement.executeUpdate(sql);
    }

    @Override
    public int delete(Object obj) throws SQLException, InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        String sql = sqlProvider.getUpdateSQLSelective(obj);
        Statement statement = connection.createStatement();
        return statement.executeUpdate(sql);
    }
}
